

import java.io.FileWriter;
import java.io.IOException;


/**
 * A three address code (TAC) instruction is composed of an operation code and three operands a,b,c
 * The operands are objects from the Operand3a class. The operation code is coded as an integer which
 * values are defined in the CGConstants interface. The meaning of the code is as follow:
 *<ul>
 *<li>	  TAC_ADD             a = b + c
 *<li>	  TAC_SUB             a = b - c
 *<li>	  TAC_MUL             a = b * c
 *<li>	  TAC_DIV             a = b / c
 *<li>	  TAC_NEG             a = -b
 *<li>	  TAC_COPY            a = b
 *<li>	  TAC_GOTO            goto a
 *<li>	  TAC_IFZ             ifz a goto b
 *<li>	  TAC_IFNZ            ifnz a goto b
 *<li>    TAC_ARG             arg a
 *<li>    TAC_CALL            a = call b ou call b
 *<li>	  TAC_RETURN          return a
 *<li>	  TAC_TABVAR          a = b[c]
 *<li>	  TAC_VARTAB          a[b] = c
 *<li>	  TAC_LABEL           label a
 *<li>	  TAC_VAR             var a
 *<li>	  TAC_BEGINFUNC
 *<li>	  TAC_ENDFUNC
 *</ul>
 *<p>  
 *  When an operand is missing, it must be replaced by the null object in the constructor. For
 *  example: i = Inst3a(TAC_LABEL, a, null, null)
 * @author MLB
 *
 */
public class Inst3a implements CGConstants{ 
	
    private int code_op;
    private Operand3a op_a;
    private Operand3a op_b;
    private Operand3a op_c;

/**
* The constructor
* @param op : integer (see CGConstants or class documentation)
* @param a : Operand3a
* @param b : Operand3a or null
* @param c : Operand3a or null
*/
public Inst3a ( int op, Operand3a a, Operand3a b, Operand3a c)
    {
	code_op = op;
	op_a = a;
	op_b = b;
	op_c = c;

    }
/**
 * Returns the operation code
 * @return int
 */
public int getOp()
    {
	return code_op;
    }
/**
 * Self explained
 * @return Operand3a
 */
public Operand3a getA()
    {
	return op_a;
    }
/**
 * Self explained
 * @return Operand3a
 */
public Operand3a getB()
    {
	return op_b;
    }
/**
 * Self explained
 * @return Operand3a
 */
public Operand3a getC()
    {
	return op_c;
    }

/**
 * no comment
 * @param o : Operand3a
 */
public void setA(Operand3a o){
	op_a = o;
}
/**
 * no comment
 * @param o : Operand3a
 */
public void setB(Operand3a o){
	op_b = o;
}

/**
 * no comment
 * @param o : Operand3a
 */
public void setC(Operand3a o){
	op_c = o;
}

/**
 * method for robustifying the toString method. If an operand is missing (null)
 * a "####" is returned in place of the name. Otherwise, the name, as defined by
 * the method getName3a is returned. 
 * @param x : the operand 
 * @return : a printable string
 */
private String the_Name(Operand3a x){
	if (x==null) return "####";
	else return x.getName3a();
}

/**
 * Print a TAC instruction.
 * This method is put here for debug purpose only.
 * TAC with type information  is just an intermediate 
 * representation of the program. The printed form lack some 
 * information to be completely equivalent to the source program.
 * <br>
 * The toString method is robustified for debug purpose. If an operand is missing (null)
 * a "####" is returned in place of the name. Otherwise, the name, as defined by
 * the method <b>getName3a</b>, is returned. 
 */
	 public String toString(){
		switch(code_op)
			 {
		    case TAC_ADD:
				  return (" "+the_Name(op_a)+
							 " = "+
							 the_Name(op_b)+
							 " + "+
							 the_Name(op_c));
		    case TAC_SUB:
				  return (" "+the_Name(op_a)+
							 " = "+
							 the_Name(op_b)+
							 " - "+
							 the_Name(op_c));
		    case TAC_MUL:
				  return (" "+the_Name(op_a)+
							 " = "+
							 the_Name(op_b)+
							 " * "+
							 the_Name(op_c));
		    case TAC_DIV:
				  return (" "+the_Name(op_a)+
							 " = "+
							 the_Name(op_b)+
							 " / "+
							 the_Name(op_c));
		    case TAC_NEG:
				  return (" "+the_Name(op_a)+
							 " = "+" - "+
							 the_Name(op_b));
			 case TAC_COPY:
				  return (" "+the_Name(op_a)+
							 " = "+
							 the_Name(op_b));
			 case TAC_GOTO:
				  return (" goto "+
							 the_Name(op_a));
				  
		    case TAC_IFZ:
				  return (" ifz "+
							 the_Name(op_a)+
							 " goto "+
							 the_Name(op_b));
		    case TAC_IFNZ:
				  return (" ifnz "+
							 the_Name(op_a)+
							 " goto "+
							 the_Name(op_b));
			 case TAC_ARG:
				  return (" arg "+
							 the_Name(op_a));
			 case TAC_CALL:
				  if (op_a!=null)
						return (" "+the_Name(op_a)+
								  " =  call "+
								  the_Name(op_b));
				  else
						return (" call "+
								  the_Name(op_b));
			 case TAC_RETURN:
				  return (" return "+
							 the_Name(op_a));
			 case TAC_LABEL:
				  return (" label "+
							 the_Name(op_a));
			 case TAC_VAR:
				  return (" var "+
							 the_Name(op_a));
			 case TAC_BEGINFUNC:
				  return (" beginfunc ");
			 case TAC_ENDFUNC:
				  return (" endfunc ");
			 case TAC_TABVAR:
				  return (" "+the_Name(op_a)+
							 " = "+
							 the_Name(op_b)+
							 " [ "+
							 the_Name(op_c)+
							 " ]");
							 
		    case TAC_VARTAB:
				  return (" "+the_Name(op_a)+
							 " [ "+
							 the_Name(op_b)+
							 " ] = "+
							 the_Name(op_c));
		    default:
				  return (" unknown TAC opcode ");
			 }
	 }
	 
	 public void print(){
		 System.out.println(this.toString());
	 }
	 
	 public void print_in_file(FileWriter fo){
		 try {
			 fo.write(this.toString()+"\n");
			 }
		 catch (IOException exc){
		 } 
	 }
} // en class Inst3a
